package com.smart.community.property.service.impl;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.springframework.cache.annotation.Cacheable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.smart.community.commons.exception.BusinessException;
import com.smart.community.commons.result.ResultCode;
import com.smart.community.feign.region.service.RegionDataFeignService;
import com.smart.community.property.mapper.BillingMethodMapper;
import com.smart.community.property.mapper.RepairOrderMapper;
import com.smart.community.property.service.DashboardService;
import com.smart.community.property.service.DataScopeService;
import com.smart.community.property.service.IPropertyCompanyCommunityService;
import com.smart.community.property.vo.DashboardBillingStandardVO;
import com.smart.community.property.vo.DashboardDataVO;
import com.smart.community.property.vo.DashboardInspectionVO;
import com.smart.community.property.vo.DashboardKpiVO;
import com.smart.community.property.vo.DashboardTrendVO;
import com.smart.community.property.vo.InspectionRecordVO;

import lombok.extern.slf4j.Slf4j;

/**
 * 驾驶舱Service实现类
 * 
 * @author Wu.Liang
 * @version 1.0.0
 * @since 2025-01-30
 */
@Slf4j
@Service
public class DashboardServiceImpl implements DashboardService {

    @Autowired
    private DataScopeService dataScopeService;
    
    @Autowired
    private RepairOrderMapper repairOrderMapper;
    
    @Autowired
    private IPropertyCompanyCommunityService propertyCompanyCommunityService;
    
    @Autowired
    private RegionDataFeignService regionDataFeignService;
    
    @Autowired
    private BillingMethodMapper billingMethodMapper;

    @Override
    @Cacheable(value = "dashboard:data", key = "#propertyCompanyId", unless = "#result == null")
    public DashboardDataVO getDashboardData(Long propertyCompanyId) throws Exception {
        log.info("获取驾驶舱完整数据，物业公司ID：{}", propertyCompanyId);
        
        // 参数验证
        if (propertyCompanyId == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "物业公司ID不能为空");
        }
        
        DashboardDataVO dashboardData = new DashboardDataVO();
        dashboardData.setKpiData(getKpiData(propertyCompanyId));
        dashboardData.setTrendData(getTrendData(propertyCompanyId, 12));
        dashboardData.setInspectionData(getInspectionData(propertyCompanyId));
        dashboardData.setBillingStandardData(getBillingStandardData(propertyCompanyId));
        
        log.info("获取驾驶舱完整数据成功，物业公司ID：{}", propertyCompanyId);
        return dashboardData;
    }

    @Override
    public DashboardKpiVO getKpiData(Long propertyCompanyId) throws Exception {
        log.info("获取KPI指标数据，物业公司ID：{}", propertyCompanyId);
        
        // 参数验证
        if (propertyCompanyId == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "物业公司ID不能为空");
        }
        
        DashboardKpiVO kpiData = new DashboardKpiVO();
        
        // 1. 获取今日维修工单统计和变化率
        int todayRepairOrders = getTodayRepairOrdersCount(propertyCompanyId);
        double repairChange = getRepairOrdersChangeRate(propertyCompanyId);
        kpiData.setTodayRepairOrders(todayRepairOrders);
        kpiData.setRepairChange(repairChange);
        
        // 2. 获取管理社区数统计
        int managedCommunities = getManagedCommunitiesCount(propertyCompanyId);
        kpiData.setManagedCommunities(managedCommunities);
        
        // 3. 获取总住户数统计
        int totalResidents = getTotalResidentsCount(propertyCompanyId);
        kpiData.setTotalResidents(totalResidents);
        
        // 4. 获取收费标准数据（用于计算其他指标）
        // List<DashboardBillingStandardVO> billingStandards = getBillingStandardData(propertyCompanyId);
        
        // 模拟数据（暂时保留，后续可扩展为真实数据）
        kpiData.setTodayIncome(new BigDecimal("12580.00"));
        kpiData.setIncomeChange(15.6);
        kpiData.setCollectionRate(94.5);
        kpiData.setExpiringThisMonth(45);
        kpiData.setRenewedThisMonth(38);
        kpiData.setRenewalRate(84.4);
        kpiData.setPaidCount(1187);
        kpiData.setUnpaidCount(69);
        
        log.info("获取KPI指标数据成功，物业公司ID：{}", propertyCompanyId);
        return kpiData;
    }

    @Override
    public DashboardTrendVO getTrendData(Long propertyCompanyId, Integer months) throws Exception {
        log.info("获取趋势数据，物业公司ID：{}，统计月数：{}", propertyCompanyId, months);
        
        // 参数验证
        if (propertyCompanyId == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "物业公司ID不能为空");
        }
        if (months == null || months <= 0) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "统计月数必须大于0");
        }
        
        DashboardTrendVO trendData = new DashboardTrendVO();
        
        // 生成月份列表
        List<String> dates = new ArrayList<>();
        List<BigDecimal> incomeData = new ArrayList<>();
        List<Integer> householdData = new ArrayList<>();
        
        LocalDate today = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M月");
        
        for (int i = months - 1; i >= 0; i--) {
            LocalDate date = today.minusMonths(i);
            dates.add(date.format(formatter));
            
            // 模拟数据，实际应该从数据库查询
            // 收入数据：20-50万元之间
            incomeData.add(new BigDecimal(String.valueOf((int) (Math.random() * 31) + 20)));
            // 户数数据：1000-2500户之间
            householdData.add((int) (Math.random() * 1501) + 1000);
        }
        
        trendData.setDates(dates);
        trendData.setIncomeData(incomeData);
        trendData.setHouseholdData(householdData);
        
        log.info("获取趋势数据成功，物业公司ID：{}", propertyCompanyId);
        return trendData;
    }

    @Override
    public DashboardInspectionVO getInspectionData(Long propertyCompanyId) throws Exception {
        log.info("获取安全检查数据，物业公司ID：{}", propertyCompanyId);
        
        // 参数验证
        if (propertyCompanyId == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "物业公司ID不能为空");
        }
        
        DashboardInspectionVO inspectionData = new DashboardInspectionVO();
        
        // 模拟数据，实际应该从数据库查询
        inspectionData.setTodayInspections(15);
        inspectionData.setTodayPassRate(100.0);
        inspectionData.setMonthInspections(156);
        inspectionData.setMonthPassRate(98.7);
        
        // 检查记录列表
        List<InspectionRecordVO> inspectionList = new ArrayList<>();
        inspectionList.add(createInspectionRecord(1, "张师傅", "电梯A栋1号", "安全运行", "合格", "2025-01-30", "A栋1单元"));
        inspectionList.add(createInspectionRecord(2, "李师傅", "消防栓", "水压测试", "合格", "2025-01-30", "B栋2单元"));
        inspectionList.add(createInspectionRecord(3, "王师傅", "监控设备", "图像清晰度", "合格", "2025-01-30", "小区大门"));
        inspectionList.add(createInspectionRecord(4, "赵师傅", "门禁系统", "刷卡功能", "合格", "2025-01-30", "C栋入口"));
        inspectionList.add(createInspectionRecord(5, "刘师傅", "照明系统", "亮度测试", "合格", "2025-01-30", "地下车库"));
        
        inspectionData.setInspectionList(inspectionList);
        
        log.info("获取安全检查数据成功，物业公司ID：{}", propertyCompanyId);
        return inspectionData;
    }

    @Override
    public List<DashboardBillingStandardVO> getBillingStandardData(Long propertyCompanyId) throws Exception {
        log.info("获取收费标准数据，物业公司ID：{}", propertyCompanyId);
        
        // 参数验证
        if (propertyCompanyId == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "物业公司ID不能为空");
        }
        
        List<DashboardBillingStandardVO> billingStandardList = new ArrayList<>();
        
        try {
            // 从数据库查询计费方式数据
            List<Map<String, Object>> billingMethods = billingMethodMapper.selectBillingMethodsByPropertyCompanyId(propertyCompanyId);
            
            if (billingMethods != null && !billingMethods.isEmpty()) {
                int index = 1;
                for (Map<String, Object> method : billingMethods) {
                    // String feeType = (String) method.get("fee_type"); // 暂时不使用
                    String buildingTypeName = (String) method.get("building_type_name");
                    String methodName = (String) method.get("method_name");
                    BigDecimal unitPrice = (BigDecimal) method.get("unit_price");
                    BigDecimal fixedAmount = (BigDecimal) method.get("fixed_amount");
                    String description = (String) method.get("description");
                    
                    // 构建服务项目名称，确保不换行
                    String serviceName = methodName;
                    if (buildingTypeName != null && !buildingTypeName.isEmpty()) {
                        serviceName = buildingTypeName + methodName;
                    }
                    
                    // 限制服务项目名称长度，避免换行
                    if (serviceName.length() > 50) {
                        serviceName = serviceName.substring(0, 47) + "...";
                    }
                    
                    // 确定价格和单位
                    BigDecimal price = unitPrice != null ? unitPrice : fixedAmount;
                    String unit = unitPrice != null ? "元/㎡" : "元";
                    
                    billingStandardList.add(createBillingStandard(index++, serviceName, price, unit, description));
                }
            } else {
                // 如果没有配置计费方式，使用默认数据
                log.warn("物业公司{}未配置计费方式，使用默认数据", propertyCompanyId);
                billingStandardList.add(createBillingStandard(1, "物业管理费", new BigDecimal("2.50"), "元/㎡", "包含公共区域清洁、绿化养护、安保服务等"));
                billingStandardList.add(createBillingStandard(2, "电梯维护费", new BigDecimal("0.80"), "元/㎡", "电梯日常维护、年检、维修等费用"));
                billingStandardList.add(createBillingStandard(3, "公共能耗费", new BigDecimal("0.60"), "元/㎡", "公共照明、水泵、监控等设备用电"));
                billingStandardList.add(createBillingStandard(4, "垃圾清运费", new BigDecimal("0.30"), "元/㎡", "生活垃圾收集、运输、处理费用"));
                billingStandardList.add(createBillingStandard(5, "绿化养护费", new BigDecimal("0.40"), "元/㎡", "小区绿化修剪、浇水、施肥等养护"));
                billingStandardList.add(createBillingStandard(6, "安保服务费", new BigDecimal("0.50"), "元/㎡", "门岗值班、巡逻、监控等安保服务"));
            }
        } catch (Exception e) {
            log.error("查询计费方式数据失败，物业公司ID：{}", propertyCompanyId, e);
            // 发生异常时使用默认数据
            billingStandardList.add(createBillingStandard(1, "物业管理费", new BigDecimal("2.50"), "元/㎡", "包含公共区域清洁、绿化养护、安保服务等"));
            billingStandardList.add(createBillingStandard(2, "电梯维护费", new BigDecimal("0.80"), "元/㎡", "电梯日常维护、年检、维修等费用"));
            billingStandardList.add(createBillingStandard(3, "公共能耗费", new BigDecimal("0.60"), "元/㎡", "公共照明、水泵、监控等设备用电"));
            billingStandardList.add(createBillingStandard(4, "垃圾清运费", new BigDecimal("0.30"), "元/㎡", "生活垃圾收集、运输、处理费用"));
            billingStandardList.add(createBillingStandard(5, "绿化养护费", new BigDecimal("0.40"), "元/㎡", "小区绿化修剪、浇水、施肥等养护"));
            billingStandardList.add(createBillingStandard(6, "安保服务费", new BigDecimal("0.50"), "元/㎡", "门岗值班、巡逻、监控等安保服务"));
        }
        
        log.info("获取收费标准数据成功，物业公司ID：{}", propertyCompanyId);
        return billingStandardList;
    }

    @Override
    public boolean hasPropertyCompanyPermission(Long userId, Long propertyCompanyId) throws Exception {
        log.info("检查用户物业公司权限，用户ID：{}，物业公司ID：{}", userId, propertyCompanyId);
        
        // 参数验证
        if (userId == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "用户ID不能为空");
        }
        if (propertyCompanyId == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "物业公司ID不能为空");
        }
        
        try {
            boolean hasPermission = dataScopeService.hasPropertyCompanyPermission(userId, propertyCompanyId);
            log.info("检查用户物业公司权限完成，用户ID：{}，物业公司ID：{}，有权限：{}", userId, propertyCompanyId, hasPermission);
            return hasPermission;
        } catch (Exception e) {
            log.warn("检查用户物业公司权限失败，用户ID：{}，物业公司ID：{}", userId, propertyCompanyId, e);
            return false;
        }
    }

    @Override
    public boolean hasAnyPropertyCompanyPermission(Long userId) throws Exception {
        log.info("检查用户是否有任何物业公司权限，用户ID：{}", userId);
        
        // 参数验证
        if (userId == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "用户ID不能为空");
        }
        
        try {
            List<Long> propertyCompanyIds = dataScopeService.getUserPropertyCompanyIds(userId);
            boolean hasPermission = propertyCompanyIds != null && !propertyCompanyIds.isEmpty();
            log.info("检查用户是否有任何物业公司权限完成，用户ID：{}，有权限：{}", userId, hasPermission);
            return hasPermission;
        } catch (Exception e) {
            log.warn("检查用户是否有任何物业公司权限失败，用户ID：{}", userId, e);
            return false;
        }
    }

    /**
     * 创建检查记录
     * 
     * @param id 记录ID
     * @param inspector 检查员
     * @param equipment 设备名称
     * @param item 检查项目
     * @param result 检查结果
     * @param time 检查时间
     * @param location 检查位置
     * @return 检查记录VO
     */
    private InspectionRecordVO createInspectionRecord(Integer id, String inspector, String equipment, 
                                                     String item, String result, String time, String location) {
        InspectionRecordVO record = new InspectionRecordVO();
        record.setId(id);
        record.setInspector(inspector);
        record.setEquipment(equipment);
        record.setItem(item);
        record.setResult(result);
        record.setTime(time);
        record.setLocation(location);
        return record;
    }

    /**
     * 创建收费标准
     * 
     * @param id 标准ID
     * @param service 服务名称
     * @param price 价格
     * @param unit 单位
     * @param description 描述
     * @return 收费标准VO
     */
    private DashboardBillingStandardVO createBillingStandard(Integer id, String service, BigDecimal price, 
                                                            String unit, String description) {
        DashboardBillingStandardVO standard = new DashboardBillingStandardVO();
        standard.setId(id);
        standard.setService(service);
        standard.setPrice(price);
        standard.setUnit(unit);
        standard.setDescription(description);
        return standard;
    }
    
    /**
     * 获取维修工单变化率
     * 严格按照《Java后端SpringBoot代码开发规范.md》Service规范实现
     * 
     * @param propertyCompanyId 物业公司ID
     * @return 维修工单变化率（百分比）
     */
    private double getRepairOrdersChangeRate(Long propertyCompanyId) {
        try {
            log.info("获取维修工单变化率，物业公司ID：{}", propertyCompanyId);
            
            // 获取物业公司关联的社区ID列表
            List<Long> communityIds = propertyCompanyCommunityService.getCommunityIdsByPropertyCompanyId(propertyCompanyId);
            if (communityIds == null || communityIds.isEmpty()) {
                log.warn("物业公司{}未关联任何社区", propertyCompanyId);
                return 0.0;
            }
            
            // 统计今日和昨日的工单数量
            int todayCount = 0;
            int yesterdayCount = 0;
            
            for (Long communityId : communityIds) {
                Integer today = repairOrderMapper.selectTodayNewOrderCount(communityId);
                Integer yesterday = repairOrderMapper.selectYesterdayNewOrderCount(communityId);
                
                if (today != null) {
                    todayCount += today;
                }
                if (yesterday != null) {
                    yesterdayCount += yesterday;
                }
            }
            
            // 计算变化率
            double changeRate = 0.0;
            if (yesterdayCount > 0) {
                changeRate = ((double) (todayCount - yesterdayCount) / yesterdayCount) * 100;
            } else if (todayCount > 0) {
                // 如果昨日为0，今日有数据，则变化率为100%
                changeRate = 100.0;
            }
            
            log.info("获取维修工单变化率成功，物业公司ID：{}，今日：{}，昨日：{}，变化率：{}%", 
                    propertyCompanyId, todayCount, yesterdayCount, changeRate);
            
            return Math.round(changeRate * 10.0) / 10.0; // 保留一位小数
            
        } catch (Exception e) {
            log.error("获取维修工单变化率失败，物业公司ID：{}", propertyCompanyId, e);
            return 0.0;
        }
    }
    
    /**
     * 获取今日维修工单数量
     * 严格按照《Java后端SpringBoot代码开发规范.md》Service规范实现
     * 
     * @param propertyCompanyId 物业公司ID
     * @return 今日维修工单数量
     */
    private int getTodayRepairOrdersCount(Long propertyCompanyId) {
        try {
            log.info("获取今日维修工单数量，物业公司ID：{}", propertyCompanyId);
            
            // 获取物业公司关联的社区ID列表
            List<Long> communityIds = propertyCompanyCommunityService.getCommunityIdsByPropertyCompanyId(propertyCompanyId);
            if (communityIds == null || communityIds.isEmpty()) {
                log.warn("物业公司{}未关联任何社区", propertyCompanyId);
                return 0;
            }
            
            // 统计所有社区的今日维修工单数量
            int totalCount = 0;
            for (Long communityId : communityIds) {
                Integer count = repairOrderMapper.selectTodayNewOrderCount(communityId);
                if (count != null) {
                    totalCount += count;
                }
            }
            
            log.info("获取今日维修工单数量成功，物业公司ID：{}，数量：{}", propertyCompanyId, totalCount);
            return totalCount;
            
        } catch (Exception e) {
            log.error("获取今日维修工单数量失败，物业公司ID：{}", propertyCompanyId, e);
            return 0;
        }
    }
    
    /**
     * 获取管理社区数量
     * 严格按照《Java后端SpringBoot代码开发规范.md》Service规范实现
     * 
     * @param propertyCompanyId 物业公司ID
     * @return 管理社区数量
     */
    private int getManagedCommunitiesCount(Long propertyCompanyId) {
        try {
            log.info("获取管理社区数量，物业公司ID：{}", propertyCompanyId);
            
            // 获取物业公司关联的社区ID列表
            List<Long> communityIds = propertyCompanyCommunityService.getCommunityIdsByPropertyCompanyId(propertyCompanyId);
            int count = communityIds != null ? communityIds.size() : 0;
            
            log.info("获取管理社区数量成功，物业公司ID：{}，数量：{}", propertyCompanyId, count);
            return count;
            
        } catch (Exception e) {
            log.error("获取管理社区数量失败，物业公司ID：{}", propertyCompanyId, e);
            return 0;
        }
    }
    
    /**
     * 获取总住户数量
     * 严格按照《Java后端SpringBoot代码开发规范.md》Service规范实现
     * 根据物业公司关联的社区ID，获取所有楼栋ID，再获取所有单元ID，再获取所有房户ID，
     * 统计所有房户ID作为查询范围，查询'住户房户关联表'，这里查询出来的房户ID集合就是实际有人居住的房户信息，
     * 最后再对查询出来的房户ID集合中的房户ID去重，得到的就是有人居住的房户数量
     * 
     * @param propertyCompanyId 物业公司ID
     * @return 总住户数量
     */
    private int getTotalResidentsCount(Long propertyCompanyId) {
        try {
            log.info("获取总住户数量，物业公司ID：{}", propertyCompanyId);
            
            // 获取物业公司关联的社区ID列表
            List<Long> communityIds = propertyCompanyCommunityService.getCommunityIdsByPropertyCompanyId(propertyCompanyId);
            if (communityIds == null || communityIds.isEmpty()) {
                log.warn("物业公司{}未关联任何社区", propertyCompanyId);
                return 0;
            }
            
            // 通过区域服务获取所有房户ID
            List<Long> allHouseholdIds = regionDataFeignService.getHouseholdIdsByCommunityIds(communityIds);
            int residentCount = allHouseholdIds != null ? allHouseholdIds.size() : 0;
            
            log.info("获取总住户数量成功，物业公司ID：{}，社区数：{}，房户总数：{}", 
                    propertyCompanyId, communityIds.size(), residentCount);
            
            return residentCount;
            
        } catch (Exception e) {
            log.error("获取总住户数量失败，物业公司ID：{}", propertyCompanyId, e);
            return 0;
        }
    }
}
